package com.karina.visualization.chart.component;

import java.util.List;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.SimplePanel;
import com.karina.visualization.chart.client.Context;
import com.karina.visualization.chart.impl.CanvasContext;
import com.karina.visualization.chart.model.ChartModel;
import com.karina.visualization.chart.model.ChartModel.DataDescriptor;
import com.karina.visualization.chart.skins.ChartPaneSkin;
import com.karina.visualization.styles.StylesManager;

abstract public class ChartWidgetBase<Model extends ChartModel<DataType>, DataType>
		extends Composite {

	protected ChartBase<Model, DataType> chart;

	private int width = 0;
	private int height = 0;
	private int effectduration = TweenEffectPlayer.DEFAULT_EFFECTION_DURATION;

	/**
	 * injected by the impl of context which is will take the GWTCanvas and make
	 * it as the graphic, than all draw behavior will be on top of it
	 */
	private final Context context = new CanvasContext();

	private final SimplePanel container;
	private DataDescriptor<DataType> descritpor;

	protected void setEffectDuration(int duration) {
		effectduration = duration;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void setDataDescriptor(DataDescriptor descriptor) {
		this.descritpor = descriptor;
	}

	public DataDescriptor<DataType> getDataDescriptor() {
		return descritpor;
	}

	public ChartWidgetBase(ChartBase<Model, DataType> chart) {

		container = new SimplePanel();
		container.setStyleName("trinity-chart");
		container.add(context.getCanvasWidget());
		initWidget(container);
		this.chart = chart;

		chart.setSkin(getSkin());
		chart.setContext(context);

	}

	/**
	 * set Data Model which is the data used by chart engine.
	 * 
	 * @param data
	 */
	protected void setData(final Model data) {
		chart.setData(data);
		chart.setLeft(30);
		chart.setTop(30);
		chart.setBottom(5);
		chart.setRight(5);
		chart.getData().setWidth(width);
		chart.getData().setHeight(height);

		if (descritpor != null) {
			data.setDataDescriptor(descritpor);
			chart.caculateSeries();
		}

		Scheduler.get().scheduleDeferred(new ScheduledCommand() {
			@Override
			public void execute() {
				boolean canPlay = false;

				if (getData() != null) {
					canPlay = true;
				}
				if (canPlay)
					chart.play(effectduration);
			}
		});
	}

	protected Model getData() {
		return chart.getData();
	}

	public void setDataProvider(List<DataType> dataProvider) {
		Model dataModel = createChartModel(dataProvider);

		setData(dataModel);
	}

	abstract protected Model createChartModel(List<DataType> dataProvider);

	/**
	 * the method should be override so that the subclass is able to provides
	 * skin for current chart
	 * 
	 * @return
	 */
	abstract public ChartPaneSkin<Model> getSkin();

	@Override
	protected void onLoad() {
		// Update chart content which will draw the chart
		chart.getUpdateManager().enable();
		chart.setVsible(true);
		chart.invalidteChartObjectModel();
	}

	@Override
	public void setWidth(String width) {

		this.width = Integer.parseInt(width);

		super.setWidth(width);
		if (chart.getData() != null)
			chart.getData().setWidth(this.width);

	}

	public void enableEffect(boolean enable) {
		chart.enableEffect(enable);
	}

	@Override
	public void setHeight(String height) {

		this.height = Integer.parseInt(height);

		super.setHeight(height);
		if (chart.getData() != null)
			chart.getData().setHeight(this.height);
	}

	public void setChartStyle(String selectorName, String styleName,
			Object value) {
		String sName = selectorName;
		if (selectorName != null && !selectorName.equals("")) {
			sName = '.' + sName;
		}
		StylesManager.getIntance().setStyle(sName, styleName, value);
	}
}
